/*
 *  (c) 2015 fullhan.com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

/*****************************************************************************
 *  Include Section
 *  add all #include here
 *****************************************************************************/
#include "net_auto_dll_tuning.h"
/*****************************************************************************
 * Define section
 * add all #define here
 *****************************************************************************/
#define NET_TUNING_FMT "NET_TUNING_ASSERT "
#define NET_TUNING_ASSERT(cond) do { \
	if (!(cond)) {\
		printf(NET_TUNING_FMT "%s:%d\n", __func__, __LINE__); \
		BUG(); \
	} \
} while (0)

#define TUNING_TIMES	10
#define	MAX_TUNING_COLUMN_SIZE		0x100
#define	MAX_TUNING_ROW_SIZE			0x100
#define MAX_REC_DL_INFO				0x100
#define INIT_DEADBEEF				0xdeadbeef
#define MAX_DLL						0x100
#define PRE_POL_PASS_TIMES_IS_OK		1

// struct pol_dll_ret g_pol_array[4] = {0};
u8 g_tuning_rec_array[MAX_TUNING_COLUMN_SIZE][MAX_TUNING_ROW_SIZE] = {0};
struct pol_dll_ret g_pol_array[4] = {0};


//below is unidimensional
//just like [fix tx_dll] :: [list all rx dll] or [list all tx_dll] :: [fix rx dll]
//the reason using unidimensional :: tx and rx are orthogonality..means tx and rx are independent
struct tuning_dl_info g_dl_info_fwd[MAX_REC_DL_INFO] = {0};
struct tuning_dl_info g_dl_info_rev[MAX_REC_DL_INFO] = {0};


__attribute__((aligned(32))) static u8 g_tuning_tx_buf[128];
__attribute__((aligned(32))) static u8 g_tuning_rx_buf[128];

char *str_to_loop_ret[] = {
	"LOOP_OK",
	"LOOP_ERR_SEND",
	"LOOP_ERR_REV_TIMEOUT",
	"LOOP_ERR_REV_ERR",
	"LOOP_ERR_REV_LEN",
	"LOOP_ERR_CMP",
};
/*****************************************************************************
 * func below..
 *****************************************************************************/
static int test_cmp(unsigned char* src,unsigned char* dst, unsigned int size){

	u32* t_src;
	u32* t_dst;
	u32 i;
	//spd up, should 4B allign
	if(size % 4){
		printf("buf size should 4B allign\n");
		NET_TUNING_ASSERT(0);
	}
	if((u32)src % 4 || (u32)dst % 4){
		printf("buf addr should 4B allign\n");
		NET_TUNING_ASSERT(0);
	}

	t_src = src;
	t_dst = dst;
	for(i = 0; i < size / 4; i++)
	{
		if(*t_src != *t_dst)
		{
			//printf("!!!!!!!!!!!!!!!!!!!!!cmp err index : %x; %x != %x\n", i,*t_src,*t_dst);
			return -1;
		}
		t_src++;
		t_dst++;
	}
	return 0;

}


int __tuning_process(struct eth_device* net_dev, u8 *tx_buf, u8* rx_buf, u32 buf_size){
	int ret;
	int times;
	int i;

	for(i = 0; i < TUNING_TIMES; i++){
		ret = net_dev->loop_send(net_dev, tx_buf, buf_size);
		if(ret != LOOP_OK){
			break;
		}
		ret = net_dev->loop_recv(net_dev, rx_buf, buf_size);
		if(ret != LOOP_OK){
			break;
		}
		ret = test_cmp(tx_buf, rx_buf, buf_size);
		if(ret != 0){
			ret = LOOP_ERR_CMP;
			break;
		}
	}
	return ret;
}

/*
-----> rx dll (row_index)
|
|
↓
tx dll(column_index)
*/

static void tuning_printf_dl(u8 p_buf[MAX_TUNING_COLUMN_SIZE][MAX_TUNING_ROW_SIZE], u32 accuracy)
{
	u32 num;
	u32 column_index, row_index;

	printf("  ");
	for(num = 0; num < MAX_TUNING_ROW_SIZE; num+=accuracy){
		printf("%2x",num);
	}
	for(column_index = 0; column_index < MAX_TUNING_COLUMN_SIZE; column_index += accuracy){
		printf("\n%2x",column_index);
		for(row_index = 0; row_index < MAX_TUNING_ROW_SIZE; row_index += accuracy){
			if(p_buf[column_index][row_index] == 0){
				printf("  ");
			}else{
				printf("%2x",p_buf[column_index][row_index]);
			}
		}
	}
	printf("\n");
}


static void init_tx_tuning_data(u8* tx_data, u32 tx_size){
	int i;
	u8 *tx_tuning;
	u32 *re_write_u32;
	unsigned int random_ret;

	srand(get_timer(0));
	for(i = 0, tx_tuning = (u8*)tx_data;
	i < tx_size;){
		random_ret = rand();
		//printf("ret random is %x\n",random_ret);
		memcpy(tx_tuning, &random_ret , 4);
		i+= 4;
		tx_tuning += 4;
	}
	re_write_u32 = (u32*)tx_data;
	//force len/type.
	re_write_u32[3] = 0x00450008;
}


int cmd_debug_tuning_process(struct eth_device* net_dev, u8 *tx_buf, u8* rx_buf, u32 buf_size, u32 tx_inv, u32 rx_inv){
	int ret;
	u32 tx,rx;

	struct eth_device * p_eth = 0;
	u32 step_size = 4;

	p_eth = eth_get_dev_by_name(eth_get_name());
	ret = p_eth->para_pol_set(p_eth, tx_inv, rx_inv);
	if(ret != 0){
		printf("para_pol_set err..\n");
		return CMD_RET_FAILURE;
	}
	//init rec array..
	memset(g_tuning_rec_array, 0, sizeof(g_tuning_rec_array));
	//memset(tx_buf, 0, buf_size);
	//list all tx and rx
	for(tx = 0; tx < MAX_TUNING_COLUMN_SIZE; tx += step_size) {
		for(rx = 0; rx < MAX_TUNING_ROW_SIZE; rx += step_size) {
			//change dll
			ret = p_eth->para_dll_set(p_eth, tx, rx);
			//dll setting to the end
			if(ret)
				break;
			//init send data and rx data...
			memset(rx_buf, 0 , buf_size);
			init_tx_tuning_data(tx_buf, buf_size);
			ret = __tuning_process(p_eth, tx_buf, rx_buf, buf_size);
			if(ret == LOOP_OK)
				g_tuning_rec_array[tx][rx] = 1;
		}
	}
	tuning_printf_dl(g_tuning_rec_array, step_size);
	return 0;
}


static int net_tuning_dll_scan(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	int ret;
	u32 tx_inv_enable;
	u32 rx_inv_enable;
	u32 spd;
	u32 list_all_inv = 0;
	struct eth_device * p_eth = 0;
	struct phy_device * p_phy = 0;

	if(argc == 2){
		spd = simple_strtoul(argv[1], NULL, 10);
		list_all_inv = 1;
	}
	else if(argc == 4){
		spd = simple_strtoul(argv[1], NULL, 10);
		tx_inv_enable = simple_strtoul(argv[2], NULL, 16);
		rx_inv_enable = simple_strtoul(argv[3], NULL, 16);
		list_all_inv = 0;
	}
	else{
		printf("EX :: net_tuning_dll_scan 10|100|1000 tx_inv[0,1] rx_inv[0,1] OR 10|100|1000\n");
		return CMD_RET_FAILURE;
	}

	p_eth = eth_get_dev_by_name(eth_get_name());
	p_phy = mdio_phydev_for_ethname(eth_get_name());

	if(!p_eth || !p_phy){
		printf("net dev [%x] or phy dev [%x] is NULL\n",(int)p_eth, (int)p_phy);
		return CMD_RET_FAILURE;
	}

	printf("speed [%d M] ..\n",spd);
	//phy loop init..
	p_phy->drv->loop_spd_set(p_phy, spd);
	p_phy->drv->loop_wait_linkup(p_phy);
	//mac loop init..
	ret = p_eth->loop_init(p_eth, spd);
	if(ret != 0){
		printf("loop init err..\n");
		return CMD_RET_FAILURE;
	}

	if(list_all_inv == 0){
		printf("[tx_inv_enable : rx_inv_enable = %x : %x]\n",tx_inv_enable, rx_inv_enable);
		cmd_debug_tuning_process(p_eth, g_tuning_tx_buf, g_tuning_rx_buf,
		sizeof(g_tuning_tx_buf), tx_inv_enable, rx_inv_enable);
		return CMD_RET_SUCCESS;
	}

	for(tx_inv_enable = 0; tx_inv_enable <= 1; tx_inv_enable++){
		for(rx_inv_enable = 0; rx_inv_enable <= 1; rx_inv_enable++){
			printf("[tx_inv_enable : rx_inv_enable = %x : %x]\n",tx_inv_enable, rx_inv_enable);
			cmd_debug_tuning_process(p_eth, g_tuning_tx_buf, g_tuning_rx_buf,
			sizeof(g_tuning_tx_buf), tx_inv_enable, rx_inv_enable);

		}
	}
	return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
 net_tuning_dll_scan, 5, 0, net_tuning_dll_scan,
 "net_tuning_dll_scan",
 ""
);

/****************auto find dll below****************/
 
void __auto_tx_dll_rec(struct eth_device *p_eth, struct tuning_dl_info *p_dl_info,
u32 rx_init_val, u32 step_size){
	int i;
	int rec_index;
	int ret;
	u8 *p_tx = g_tuning_tx_buf;
	u8 *p_rx = g_tuning_rx_buf;

	init_tx_tuning_data(g_tuning_tx_buf, sizeof(g_tuning_tx_buf));
	for(i = 0, rec_index = 0; i < MAX_DLL; i += step_size, rec_index++){
		ret = p_eth->para_dll_set(p_eth, i, rx_init_val);
		//dll setting to the end
		if(ret)
			break;
		//spd up....just set some pos
		//memset(g_tuning_rx_buf, 0, g_tuning_rx_buf);
		p_rx[i % sizeof(g_tuning_tx_buf)] = rand();
		p_tx[i % sizeof(g_tuning_tx_buf)] = rand();
		ret = __tuning_process(p_eth, p_tx, p_rx, sizeof(g_tuning_tx_buf));
		p_dl_info[rec_index].tx_dl = i;
		p_dl_info[rec_index].rx_dl = rx_init_val;
		if(ret == LOOP_OK)
			p_dl_info[rec_index].result = "pass";
		else
			p_dl_info[rec_index].result = str_to_loop_ret[ret];
	}	
}



void __auto_rx_dll_rec(struct eth_device *p_eth, struct tuning_dl_info *p_dl_info,
u32 tx_init_val, u32 step_size){

	int i;
	int rec_index;
	int ret;
	u8 *p_tx = g_tuning_tx_buf;
	u8 *p_rx = g_tuning_rx_buf;

	init_tx_tuning_data(g_tuning_tx_buf, sizeof(g_tuning_tx_buf));
	for(i = 0, rec_index = 0; i < MAX_DLL; i += step_size, rec_index++){
		ret = p_eth->para_dll_set(p_eth, tx_init_val, i);
		//dll setting to the end
		if(ret)
			break;
		//spd up....just set some pos
		//memset(g_tuning_rx_buf, 0, g_tuning_rx_buf);
		p_rx[i % sizeof(g_tuning_tx_buf)] = rand();
		p_tx[i % sizeof(g_tuning_tx_buf)] = rand();
		ret = __tuning_process(p_eth, p_tx, p_rx, sizeof(g_tuning_tx_buf));
		p_dl_info[rec_index].tx_dl = tx_init_val;
		p_dl_info[rec_index].rx_dl = i;
		if(ret == LOOP_OK)
			p_dl_info[rec_index].result = "pass";
		else
			p_dl_info[rec_index].result = str_to_loop_ret[ret];
	}

}




int __pre_tuning_pol(struct eth_device *p_eth, struct phy_device *p_phy, u32 spd, struct pol_dll_ret *p_pol){
	int ret;

	u32 rec_index = 0;	
	u32 step_size;
	u32 rx_init_val;
	u32 tx_inv = DLL_POL_FWD;
	u32 rx_inv = DLL_POL_FWD;

	struct tuning_result_info dl_result = {0};

#define PRE_POL_PASS_TIMES_IS_OK	1
	u32 pass_times;

	if(!p_eth || !p_phy){
		printf("net dev [%x] or phy dev [%x] is NULL\n",(int)p_eth, (int)p_phy);
		return -1;
	}
	if(!p_phy->drv){
		printf("p_phy->drv is NULL\n");
		return -1;
	}
	if(!p_phy->drv->loop_spd_set || !p_phy->drv->loop_wait_linkup){
		printf("loop_spd_set [%x] or loop_wait_linkup [%x] is NULL\n",
		(int)p_phy->drv->loop_spd_set, (int)p_phy->drv->loop_wait_linkup);
		return -1;
	}
	//phy loop init..
	ret = p_phy->drv->loop_spd_set(p_phy, spd);
	if(ret != 0){
		printf("loop_spd_set err..\n");
		return -1;
	}	
	ret = p_phy->drv->loop_wait_linkup(p_phy);
	if(ret != 0){
		printf("loop_wait_linkup err..\n");
		return -1;
	}	
	//mac loop init..
	ret = p_eth->loop_init(p_eth, spd);
	if(ret != 0){
		printf("loop init err..\n");
		return -1;
	}
	//step 1 :: find valid tx and rx pol
	step_size = 0x10;
	rec_index = 0;
	for(tx_inv = DLL_POL_FWD; tx_inv <=DLL_POL_REV; tx_inv++){
		for(rx_inv = DLL_POL_FWD; rx_inv <=DLL_POL_REV; rx_inv++){
			ret = p_eth->para_pol_set(p_eth, tx_inv, rx_inv);
			if(ret != 0){
				printf("para_pol_set err..\n");
				return -2;
			}
			pass_times = 0;
			for(rx_init_val = 0; rx_init_val < MAX_DLL; rx_init_val += step_size){
				dl_info_init(g_dl_info_fwd, MAX_REC_DL_INFO);
				__auto_tx_dll_rec(p_eth, g_dl_info_fwd, rx_init_val, step_size);
				memset(&dl_result, 0, sizeof(dl_result));
				dl_result.tx_or_rx = TUNING_PARSE_TX_DL_REC;
				ret = tuning_parse_dl_rec(g_dl_info_fwd, MAX_REC_DL_INFO, &dl_result);
				if(ret != 0){
					pass_times = 0;
					continue;
				}
				//100M or 10M pass win must > 5 ..
				if((spd != 1000) && (dl_result.pass_win_len) < 5){
					pass_times = 0;
					continue;
				}
				//if have pass win...
				pass_times++;
				//need seuqent PRE_POL_PASS_TIMES_IS_OK times
				if(pass_times == PRE_POL_PASS_TIMES_IS_OK){
					//dump_dl_info(g_dl_info_fwd, MAX_REC_DL_INFO);
					// printf("[%dM] tx inv : rx inv = %x : %x\n",spd, tx_inv, rx_inv);
					// dump_dl_result(&dl_result);
					break;
				}
			}

			p_pol[rec_index].tx_pol = tx_inv;
			p_pol[rec_index].rx_pol = rx_inv;
			if(pass_times == PRE_POL_PASS_TIMES_IS_OK){
				p_pol[rec_index].result = "pass";
			}else{
				p_pol[rec_index].result = "fail";
			}
			rec_index++;
		}
	}
	return 0;
}

int pre_tuning_pol(struct eth_device *p_eth, struct phy_device *p_phy, u32 spd){
	return __pre_tuning_pol(p_eth, p_phy, spd, g_pol_array);
}

void dump_pol_dll_info(struct pol_dll_ret *p_pol, u32 size, u32 spd){
	int i;

	for(i = 0; i < size; i++, p_pol++){
		printf("---[%dM]  [%d]---\n", spd, i);
		printf("\tTX_POL :: %s\n", p_pol->tx_pol == DLL_POL_FWD ? "FWD" : "REV");
		printf("\tRX_POL :: %s\n", p_pol->rx_pol == DLL_POL_FWD ? "FWD" : "REV");
		printf("\tTX_DLL :: 0x%x\n", p_pol->tx_dll);
		printf("\tRX_DLL :: 0x%x\n", p_pol->rx_dll);
		printf("\tRESULT :: %s\n", p_pol->result);
	}
}

int auto_tx_dll_rec(struct eth_device *p_eth, struct phy_device *p_phy, u32 spd, struct pol_dll_ret *usr_ret){

	int i;
	int ret;
	int pol_sw = -1;
	u32 tx_step_size = 0x08;
	u32 rx_step_size = 0x10;
	u32 rx_init_val;
	u32 pass_times = 0;
	struct tuning_result_info dl_best_fwd_result = {0};
	struct tuning_result_info dl_best_rev_result = {0};
	struct pol_dll_ret best_fwd_pol_dll = {0};
	struct pol_dll_ret best_rev_pol_dll = {0};
	struct tuning_result_info dl_temp_result = {0};
	struct pol_dll_ret *p_pol_dll = 0;
	struct tuning_dl_info *p_dl_info = 0;
	struct tuning_result_info *p_dl_result = 0;
	u32 dll_test_size = MAX_DLL / tx_step_size;

	// if(spd == 1000)
	// 	rx_step_size = 4;

	dl_info_init(g_dl_info_fwd, MAX_REC_DL_INFO);
	dl_info_init(g_dl_info_rev, MAX_REC_DL_INFO);
	//tuning all pass tx pol....
	for(i = 0; i < 4; i++){
		//pass failed pol
		if (strcmp(g_pol_array[i].result, "pass") != 0){
			continue;
		}
		//pass same tx pol
		if(pol_sw == g_pol_array[i].tx_pol){
			continue;
		}
		pol_sw = g_pol_array[i].tx_pol;
		if(pol_sw == DLL_POL_FWD){
			p_dl_info = g_dl_info_fwd;
			p_dl_result = &dl_best_fwd_result;
			p_pol_dll = &best_fwd_pol_dll;
		}
		else{
			p_dl_info = g_dl_info_rev;
			p_dl_result = &dl_best_rev_result;
			p_pol_dll = &best_rev_pol_dll;
		}

		//only try pre pol pass & tx pol only
		p_eth->para_pol_set(p_eth, g_pol_array[i].tx_pol, g_pol_array[i].rx_pol);
		//pass_times = 0;
		for(rx_init_val = 0; rx_init_val < MAX_DLL; rx_init_val += rx_step_size){
			dl_info_init(p_dl_info, dll_test_size);
			__auto_tx_dll_rec(p_eth, p_dl_info, rx_init_val, tx_step_size);
			memset(&dl_temp_result, 0, sizeof(dl_temp_result));
			dl_temp_result.tx_or_rx = TUNING_PARSE_TX_DL_REC;
			ret = tuning_parse_dl_rec(p_dl_info, dll_test_size, &dl_temp_result);

			if(ret != 0){
				//pass_times = 0;
				continue;
			}
			if(p_dl_result->pass_win_len < dl_temp_result.pass_win_len){
				memcpy(p_dl_result, &dl_temp_result, sizeof(struct tuning_result_info));
				//update pol_dll
				p_pol_dll->tx_pol = g_pol_array[i].tx_pol;
				p_pol_dll->tx_dll = p_dl_result->p_dl_mid->tx_dl;
				p_pol_dll->result = "pass";
			}
		}
	}

	//ok now... will goto parse tuning info below..
	//anyway...better chose fwd...so '>='

#if(0)
	printf("fwd info ::\n");
	dump_dl_result(&dl_best_fwd_result);
	printf("rev info ::\n");
	dump_dl_result(&dl_best_rev_result);
#endif
	if(dl_best_fwd_result.pass_win_len >= dl_best_rev_result.pass_win_len){
		p_dl_result = &dl_best_fwd_result;
		p_pol_dll = &best_fwd_pol_dll;
	}
	else{
		p_dl_result = &dl_best_rev_result;
		p_pol_dll = &best_rev_pol_dll;
	}


	//if tx fwd and last to the endline...
	if((p_pol_dll->tx_pol == DLL_POL_FWD) && (p_dl_result->pass_win_ed == (dll_test_size - 1)))
		p_pol_dll->tx_dll = p_dl_result->p_dl_end->tx_dl;
	else if((p_pol_dll->tx_pol == DLL_POL_REV) && (p_dl_result->pass_win_st == 0))
		p_pol_dll->tx_dll = p_dl_result->p_dl_st->tx_dl;
	else{
		//no need to update...use mid val..
	}
	//ok...we got the best tx pol and tx dll, and we will use these for rx tuning..
	memcpy(usr_ret, p_pol_dll, sizeof(struct pol_dll_ret));
	return 0;
}


int auto_rx_dll_rec(struct eth_device *p_eth, struct phy_device *p_phy, u32 spd, struct pol_dll_ret *usr_ret){

	int i;
	int pol_sw = -1;
	u32 rx_step_size = 0x08;
	u32 tx_init_val;
	u32 dll_test_size = MAX_DLL / rx_step_size;
	struct tuning_result_info dl_best_fwd_result = {0};
	struct tuning_result_info dl_best_rev_result = {0};
	struct pol_dll_ret best_fwd_pol_dll = {0};
	struct pol_dll_ret best_rev_pol_dll = {0};
	struct tuning_result_info dl_temp_result = {0};
	struct pol_dll_ret *p_pol_dll = 0;
	struct tuning_dl_info *p_dl_info = 0;
	struct tuning_result_info *p_dl_result = 0;

	dl_info_init(g_dl_info_fwd, MAX_REC_DL_INFO);
	dl_info_init(g_dl_info_rev, MAX_REC_DL_INFO);

	//add check pre usr tx if ok....
	if (strcmp(usr_ret->result, "pass") != 0) {
		printf("pre tx tuning not pass.......\n");
		NET_TUNING_ASSERT(0);
	}
	tx_init_val = usr_ret->tx_dll;
	//tuning all pass rx pol....
	for(i = 0; i < 4; i++){
		//pass failed pol
		if (strcmp(g_pol_array[i].result, "pass") != 0){
			continue;
		}
		//pass same rx pol
		if(pol_sw == g_pol_array[i].rx_pol){
			continue;
		}
		pol_sw = g_pol_array[i].rx_pol;
		if(pol_sw == DLL_POL_FWD){
			p_dl_info = g_dl_info_fwd;
			p_dl_result = &dl_best_fwd_result;
			p_pol_dll = &best_fwd_pol_dll;
		}
		else{
			p_dl_info = g_dl_info_rev;
			p_dl_result = &dl_best_rev_result;
			p_pol_dll = &best_rev_pol_dll;
		}

		//fix tx pol for rx tuning.
		p_eth->para_pol_set(p_eth, usr_ret->tx_pol, g_pol_array[i].rx_pol);
		dl_info_init(p_dl_info, dll_test_size);
		__auto_rx_dll_rec(p_eth, p_dl_info, tx_init_val, rx_step_size);
		memset(&dl_temp_result, 0, sizeof(dl_temp_result));
		dl_temp_result.tx_or_rx = TUNING_PARSE_RX_DL_REC;
		tuning_parse_dl_rec(p_dl_info, dll_test_size, &dl_temp_result);
		if(p_dl_result->pass_win_len < dl_temp_result.pass_win_len){
			memcpy(p_dl_result, &dl_temp_result, sizeof(struct tuning_result_info));
			//update pol_dll
			p_pol_dll->rx_pol = g_pol_array[i].rx_pol;
			p_pol_dll->rx_dll = p_dl_result->p_dl_mid->rx_dl;
			p_pol_dll->result = "pass";
		}
	}

#if(0)
	printf("fwd info ::\n");
	dump_dl_result(&dl_best_fwd_result);
	printf("rev info ::\n");
	dump_dl_result(&dl_best_rev_result);
#endif

	//ok now... will goto parse tuning info below..
	//anyway...better chose fwd...so '>='
	if(dl_best_fwd_result.pass_win_len >= dl_best_rev_result.pass_win_len){
		p_dl_result = &dl_best_fwd_result;
		p_pol_dll = &best_fwd_pol_dll;
	}
	else{
		p_dl_result = &dl_best_rev_result;
		p_pol_dll = &best_rev_pol_dll;
	}

	//if tx fwd and last to the endline...
	if((p_pol_dll->rx_pol == DLL_POL_FWD) && (p_dl_result->pass_win_ed == (dll_test_size - 1)))
		p_pol_dll->rx_dll = p_dl_result->p_dl_end->rx_dl;
	else if((p_pol_dll->rx_pol == DLL_POL_REV) && (p_dl_result->pass_win_st == 0))
		p_pol_dll->rx_dll = p_dl_result->p_dl_st->rx_dl;
	else{
		//no need to update...use mid val..
	}
	usr_ret->rx_pol = p_pol_dll->rx_pol;
	usr_ret->rx_dll = p_pol_dll->rx_dll;
	return 0;

}

